#include <stdio.h>
#include <string.h>

#include "gs.h"
#include "tank.h"
#include "compensated.h"
#include "dgl.h"
#include "alarm.h"

int gs_tank_is_wrong(GS_TANK* tank)
{
    int ret;

    pthread_mutex_lock(&tank->lock);

    ret = (tank->oil >= tank->height || tank->oil <= tank->water ||
            tank->water >= tank->height);
    
    pthread_mutex_unlock(&tank->lock);

    return ret;    
}

int gs_tank_is_alarm(GS_TANK* tank)
{
    int ret;
    int o1, w1, t1, o2, w2, t2;

    pthread_mutex_lock(&tank->lock);

    o1 = tank->o_cache[3] > tank->o_upper || tank->o_cache[3] < tank->o_lower;
    w1 = tank->w_cache[3] > tank->w_upper || tank->w_cache[3] < tank->w_lower;
    t1 = tank->t_cache[3] > tank->t_upper || tank->t_cache[3] < tank->t_lower;
    
    o2 = tank->o_cache[2] > tank->o_upper || tank->o_cache[2] < tank->o_lower;
    w2 = tank->w_cache[2] > tank->w_upper || tank->w_cache[2] < tank->w_lower;
    t2 = tank->t_cache[2] > tank->t_upper || tank->t_cache[2] < tank->t_lower;

    pthread_mutex_unlock(&tank->lock);

//    printf("o1 = %d w1 = %d t1 = %d\n", o1, w1, t1);
//    printf("o2 = %d w2 = %d t2 = %d\n", o2, w2, t2);


    ret = ((o1 == 1 && o2 == 0) || (w1 == 1 && 0 == w2) || (t1 == 1 && 0 == t2));

    // printf ("ret = %d\n", ret);
    return ret;
}

GS_TANK* gs_tank_by_addr(unsigned char addr)
{
    int i;


    for (i=0; i<g_gs.tanks_nr; i++)
    {
        if (addr == g_gs.tanks[i].addr)
        {
            return &g_gs.tanks[i];
        }
    }

    return NULL;
}

long gs_tank_get_alarm(GS_TANK* tank)
{
    long alarm = 0;

    pthread_mutex_lock(&tank->lock);

    if (tank->oil >= tank->o_uupper)
        alarm |= ALARM_O_UUPPER;
    else if (tank->oil <= tank->o_lower)
        alarm |= ALARM_O_LLOWER;
    else if (tank->oil > tank->o_upper && tank->oil < tank->o_uupper)
        alarm |= ALARM_O_UPPER;
    else if (tank->oil < tank->o_lower && tank->oil > tank->o_lower)
        alarm |= ALARM_O_LOWER;
    else 
        alarm &= ~ALARM_O_MASK;

    /* 判断水位报警 */
    if (tank->water >= tank->w_upper)
        alarm |= ALARM_W_UPPER;
    else if (tank->water <= tank->w_lower)
        alarm |= ALARM_W_LOWER;
    else 
        alarm &= ~ALARM_W_MASK;

    /* 判断温度报警 */
    if (tank->temp >= tank->t_upper)
        alarm |= ALARM_T_UPPER;
    else if (tank->temp <= tank->t_lower)
        alarm |= ALARM_T_LOWER;
    else 
        alarm &= ~ALARM_T_MASK;

    pthread_mutex_unlock(&tank->lock);

    return alarm;
}

int gs_tank_get_addr(GS_TANK* tank, unsigned char* addr)
{
    pthread_mutex_lock(&tank->lock);

    *addr = tank->addr;

    pthread_mutex_unlock(&tank->lock);

    return 0;
}

double gs_tank_get_volume(GS_TANK* tank, double oil)
{
    int ret;
    double gross, net;
    // FILE* fp = NULL;
    
    pthread_mutex_lock(&tank->lock);

#if 0
    ret = gs_hctable_fp(tank->table_id, &fp);
    if (ret != 0) {
        pthread_mutex_unlock(&tank->lock);
        return ret;
    }
#endif
    ret = gs_hctable_data(tank->table, oil, &gross);
    if (ret != 0) {
        pthread_mutex_unlock(&tank->lock);
        return ret;
    }
    
    ret = gs_compensated_data(gross, tank->t1, &net);
    if (ret != 0) {
        pthread_mutex_unlock(&tank->lock);
        return ret;
    }

    pthread_mutex_unlock(&tank->lock);
    return net;
}

/* only handle follow case: 
 * 1. begin add oil into tank  4=3=2=1=0 4>=3>2=1=0 
 * 2. begin move oil from tank 4=3=2=1=0 4<=3<2=1=0
 * 3. end add oil into tank  4=3=2>1>=0 4=3=2=1=0
 * 4. end move oil fro tank  4=3=2<1<=0 4=3=2=1
 * ignor follow case:
 * 4>3>2>1>0 4<3<2<1<0
 * 4<3<2<1<0 4>3>2>1>0 
 */
void gs_tank_is_oiling(GS_TANK *tank)
{
	double o, w, t;
	int ret = -1;

	o = tank->oil;
	w = tank->water;
	t = tank->temp;

	if (tank->cache < 2) {
		tank->o_cache[tank->cache] = o;
		tank->w_cache[tank->cache] = w;
		tank->t_cache[tank->cache] = t;
		tank->cache++;
		return;
	}
	
	// begin up: 4>=3>2=1=0
	if (((long)o >= (long) tank->o_cache[3]) &&
			((long) tank->o_cache[3] >  (long) tank->o_cache[2]) && 
			((long) tank->o_cache[2] == (long) tank->o_cache[1]) && 
			((long) tank->o_cache[1] == (long) tank->o_cache[0])) {
		ret = 1;
	}
	// end up: 4=3=2>1>=0
	else if (((long) o == (long) tank->o_cache[3]) && 
			((long) tank->o_cache[3] == (long) tank->o_cache[2]) && 
			((long) tank->o_cache[2] >  (long) tank->o_cache[1]) &&
			((long) tank->o_cache[1] >= (long) tank->o_cache[0])) {
		ret = 2;
	}
	// begin down: 4<=3<2=1=0
	else if (((long) o <= (long) tank->o_cache[3]) && 
			((long) tank->o_cache[3] <  (long) tank->o_cache[2]) && 
			((long) tank->o_cache[2] == (long) tank->o_cache[1]) &&
			((long) tank->o_cache[1] == (long) tank->o_cache[0])) {
		ret = 3;
	}
	// end up: 4=3=2<1<=0
	else if (((long) o == (long) tank->o_cache[3]) && 
			((long) tank->o_cache[3] == (long) tank->o_cache[2]) && 
			((long) tank->o_cache[2] <  (long) tank->o_cache[1]) &&
			((long) tank->o_cache[1] <= (long) tank->o_cache[0])) {
		ret = 4;
	}
	// stop
	else if (((long) o == (long) tank->o_cache[3]) && 
			((long) tank->o_cache[3] ==  (long) tank->o_cache[2]) && 
			((long) tank->o_cache[2] == (long) tank->o_cache[1]) &&
			((long) tank->o_cache[1] == (long) tank->o_cache[0])) {
		ret = 0;
	}


	// begin add oil into tank
	if (tank->state == 0 && ret == 1) {
		;
	}
	// begin move oil from tank
	else if (tank->state == 0 && ret == 2) {
		;
	}
	// end add oil into tank
	else if (tank->state == 1 && ret == 0) {
		;
	}
	// end move oil from tank
	else if (tank->state == 2 && ret == 0) {
		;
	}

	tank->state = ret;
}

static char* gs_get_date_str(struct tm* tm, char* buf, int len)
{
	if (len < 9)
		return NULL;

	sprintf(buf, "%4d%02d%02d", 
			tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);

	return buf;
}

static char* gs_get_currdate_str(char *buf, int len)
{
	time_t now_t;
	struct tm* curr;
	time(&now_t);
	curr = localtime(&now_t);
	return gs_get_date_str(curr, buf, len);
}

void gs_tank_save_oilling(GS_TANK *tank)
{
	FILE* fp;
	char filename[16];
	
	gs_get_currdate_str (filename, sizeof(filename));
	fp = fopen(strcat("./data/", filename), "a+");
	
	/* 'gs code' 'tank id' 'begin' 'begin oil' 'end' 'end oil' 'add' */
//	fprintf(fp, "%d\t
	
	

}

int gs_tank_data(GS_TANK *tank)
{
    DGL_DATA data;
    int ret;
    int addr;

    addr = tank->addr;
    ret = gs_dgl_data(addr, &data);

    
    if (ret == 0) {
        int i;

        tank->oil = data.oil + tank->oil_b;
        tank->water = data.water + tank->water_b;
        tank->t1 = tank->t2 = tank->t3 = tank->t4 = tank->t5 = data.temp;
        tank->temp = data.temp;

        for (i=0; i<3; i++) {
            tank->o_cache[i] = tank->o_cache[i+1];
            tank->w_cache[i] = tank->w_cache[i+1];
            tank->t_cache[i] = tank->t_cache[i+1];
        }

        tank->o_cache[3] = tank->oil;
        tank->w_cache[3] = tank->water;
        tank->t_cache[3] = tank->temp;
    }
    else {
        tank->oil = 0;
        tank->water = 0;
        tank->t1 = tank->t2 = tank->t3 = tank->t4 = tank->t5 = 0;
        tank->temp = 0;

    }

    if (gs_tank_is_alarm(tank)) {
        printf ("alarm!!!!!!!!!!\n");
        gs_alarm_save(tank);

        if (gs_tank_alarm_callback)
            gs_tank_alarm_callback(tank);
    }

    if (gs_tank_data_callback)
        gs_tank_data_callback(tank);

    return ret;
}
